Add a notify function to GdkContentProvider
authorEmmanuele Bassi <ebassi@gnome.org>
Tue, 11 Feb 2020 17:24:01 +0000 (17:24 +0000)
committerEmmanuele Bassi <ebassi@gnome.org>
Thu, 13 Feb 2020 14:53:25 +0000 (14:53 +0000)
The callback-based content providers need a GDestroyNotify function to
free the data passed to them on construction, otherwise they are going
to leak.

demos/gtk-demo/clipboard.c
demos/icon-browser/iconbrowserwin.c
gdk/gdkcontentproviderimpl.c
gdk/gdkcontentproviderimpl.h
gtk/gtkcolorbutton.c
gtk/gtkcolorswatch.c
gtk/gtkiconview.c
gtk/gtknotebook.c
gtk/gtkplacessidebar.c
gtk/gtktreeview.c
tests/testdnd2.c

index e71fb47047fd696c679379a7c361e75b39e7e748..c5a83d7e05c5ddf6c868b7943db2d7c235c00874 100644 (file)
@@ -154,7 +154,7 @@ prepare_drag (GtkDragSource *source,
               double         y,
               GtkWidget     *image)
 {
-  return gdk_content_provider_new_with_callback (GDK_TYPE_TEXTURE, get_texture, image);
+  return gdk_content_provider_new_with_callback (GDK_TYPE_TEXTURE, get_texture, image, NULL);
 }
 
 static void
index c0fe8250317522b37d220d3bda260da0ad8352c7..d094c029d1ea78bc27d2ab06ef575a130f5a859d 100644 (file)
@@ -444,7 +444,7 @@ setup_image_dnd (GtkWidget *image)
   GtkDragSource *source;
 
   source = gtk_drag_source_new ();
-  content = gdk_content_provider_new_with_callback (GDK_TYPE_TEXTURE, get_texture, image);
+  content = gdk_content_provider_new_with_callback (GDK_TYPE_TEXTURE, get_texture, image, NULL);
   gtk_drag_source_set_content (source, content);
   g_object_unref (content);
   g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), image);
@@ -458,7 +458,7 @@ setup_scalable_image_dnd (GtkWidget *image)
   GtkDragSource *source;
 
   source = gtk_drag_source_new ();
-  content = gdk_content_provider_new_with_callback (G_TYPE_FILE, get_file, image);
+  content = gdk_content_provider_new_with_callback (G_TYPE_FILE, get_file, image, NULL);
   gtk_drag_source_set_content (source, content);
   g_object_unref (content);
 
index c114e8c3b2081520e16ddf6ff09003beb908784c..e5c86a396cdfefe18b23941f08b2c5cd57c274fb 100644 (file)
@@ -295,6 +295,7 @@ struct _GdkContentProviderCallback
   GType type;
   GdkContentProviderGetValueFunc func;
   gpointer data;
+  GDestroyNotify notify;
 };
 
 struct _GdkContentProviderCallbackClass
@@ -330,10 +331,28 @@ gdk_content_provider_callback_get_value (GdkContentProvider  *provider,
   return GDK_CONTENT_PROVIDER_CLASS (gdk_content_provider_callback_parent_class)->get_value (provider, value, error);
 }
 
+static void
+gdk_content_provider_callback_dispose (GObject *gobject)
+{
+  GdkContentProviderCallback *self = GDK_CONTENT_PROVIDER_CALLBACK (gobject);
+
+  if (self->notify != NULL)
+    self->notify (self->data);
+
+  self->func = NULL;
+  self->data = NULL;
+  self->notify = NULL;
+
+  G_OBJECT_CLASS (gdk_content_provider_callback_parent_class)->dispose (gobject);
+}
+
 static void
 gdk_content_provider_callback_class_init (GdkContentProviderCallbackClass *class)
 {
   GdkContentProviderClass *provider_class = GDK_CONTENT_PROVIDER_CLASS (class);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+
+  gobject_class->dispose = gdk_content_provider_callback_dispose;
 
   provider_class->ref_formats = gdk_content_provider_callback_ref_formats;
   provider_class->get_value = gdk_content_provider_callback_get_value;
@@ -345,10 +364,12 @@ gdk_content_provider_callback_init (GdkContentProviderCallback *content)
 }
 
 /**
- * gdk_content_provider_new_for_callback:
+ * gdk_content_provider_new_for_callback: (constructor)
  * @type: the type that the callback provides
- * @func: callback to populate a #GValue
+ * @func: (not nullable): callback to populate a #GValue
  * @data: (closure): data that gets passed to @func
+ * @notify: a function to be called to free @data when the content provider
+ *   goes away
  *
  * Create a content provider that provides data that is provided via a callback.
  *
@@ -357,14 +378,18 @@ gdk_content_provider_callback_init (GdkContentProviderCallback *content)
 GdkContentProvider *
 gdk_content_provider_new_with_callback (GType                          type,
                                         GdkContentProviderGetValueFunc func,
-                                        gpointer                       data)
+                                        gpointer                       data,
+                                        GDestroyNotify                 notify)
 {
   GdkContentProviderCallback *content;
 
+  g_return_val_if_fail (func != NULL, NULL);
+
   content = g_object_new (GDK_TYPE_CONTENT_PROVIDER_CALLBACK, NULL);
   content->type = type;
   content->func = func;
   content->data = data;
+  content->notify = notify;
   
   return GDK_CONTENT_PROVIDER (content);
 }
@@ -382,6 +407,7 @@ struct _GdkContentProviderCallback2
   GdkContentFormats *formats;
   GdkContentProviderGetBytesFunc func;
   gpointer data;
+  GDestroyNotify notify;
 };
 
 struct _GdkContentProviderCallback2Class
@@ -472,10 +498,28 @@ gdk_content_provider_callback2_write_mime_type_finish (GdkContentProvider *provi
   return g_task_propagate_boolean (G_TASK (result), error);
 }
 
+static void
+gdk_content_provider_callback2_dispose (GObject *gobject)
+{
+  GdkContentProviderCallback2 *self = GDK_CONTENT_PROVIDER_CALLBACK2 (gobject);
+
+  if (self->notify != NULL)
+    self->notify (self->data);
+
+  self->notify = NULL;
+  self->data = NULL;
+  self->func = NULL;
+
+  G_OBJECT_CLASS (gdk_content_provider_callback2_parent_class)->dispose (gobject);
+}
+
 static void
 gdk_content_provider_callback2_class_init (GdkContentProviderCallback2Class *class)
 {
   GdkContentProviderClass *provider_class = GDK_CONTENT_PROVIDER_CLASS (class);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+
+  gobject_class->dispose = gdk_content_provider_callback2_dispose;
 
   provider_class->ref_formats = gdk_content_provider_callback2_ref_formats;
   provider_class->write_mime_type_async = gdk_content_provider_callback2_write_mime_type_async;
@@ -491,7 +535,9 @@ gdk_content_provider_callback2_init (GdkContentProviderCallback2 *content)
  * gdk_content_provider_new_with_formats:
  * @formats: formats to advertise
  * @func: callback to populate a #GValue
- * @data: data that gets passed to @func
+ * @data: (closure func): data that gets passed to @func
+ * @notify: a function called to free @data when the content provider
+ *   goes away
  *
  * Create a content provider that provides data that is provided via a callback.
  *
@@ -500,13 +546,15 @@ gdk_content_provider_callback2_init (GdkContentProviderCallback2 *content)
 GdkContentProvider *
 gdk_content_provider_new_with_formats (GdkContentFormats              *formats,
                                        GdkContentProviderGetBytesFunc  func,
-                                       gpointer                        data)
+                                       gpointer                        data,
+                                       GDestroyNotify                  notify)
 {
   GdkContentProviderCallback2 *content;
   content = g_object_new (GDK_TYPE_CONTENT_PROVIDER_CALLBACK2, NULL);
   content->formats = gdk_content_formats_union_serialize_mime_types (gdk_content_formats_ref (formats));
   content->func = func;
   content->data = data;
+  content->notify = notify;
   
   return GDK_CONTENT_PROVIDER (content);
 }
index 19ac6969e134056ca327512bb50d495adc7b8f02..cea0b6b667da75e144c24d3e993c3ed567e3afb8 100644 (file)
@@ -41,7 +41,8 @@ typedef void (*GdkContentProviderGetValueFunc) (GValue   *value,
 GDK_AVAILABLE_IN_ALL
 GdkContentProvider *    gdk_content_provider_new_with_callback (GType                           type,
                                                                 GdkContentProviderGetValueFunc  func,
-                                                                gpointer                        data);
+                                                                gpointer                        data,
+                                                                GDestroyNotify                  notify);
 
 typedef GBytes * (*GdkContentProviderGetBytesFunc) (const char *mime_type,
                                                     gpointer    data);
@@ -49,7 +50,8 @@ typedef GBytes * (*GdkContentProviderGetBytesFunc) (const char *mime_type,
 GDK_AVAILABLE_IN_ALL
 GdkContentProvider *    gdk_content_provider_new_with_formats  (GdkContentFormats              *formats,
                                                                 GdkContentProviderGetBytesFunc  func,
-                                                                gpointer                        data);
+                                                                gpointer                        data,
+                                                                GDestroyNotify                  notify);
 
 G_END_DECLS
 
index 77e5086941de98f7a38257da58f45c512a8155ba..7ae781cd475e8e211a9feafe47dc245c0f5f9527 100644 (file)
@@ -333,7 +333,7 @@ gtk_color_button_init (GtkColorButton *button)
   gdk_content_formats_unref (targets);
 
   source = gtk_drag_source_new ();
-  content = gdk_content_provider_new_with_callback (GDK_TYPE_RGBA, get_rgba_value, button);
+  content = gdk_content_provider_new_with_callback (GDK_TYPE_RGBA, get_rgba_value, button, NULL);
   gtk_drag_source_set_content (source, content);
   g_object_unref (content);
   g_signal_connect (source, "drag-begin", G_CALLBACK (gtk_color_button_drag_begin), button);
index 270556ed78fcf5d342d662384eae789b8c2462f1..e66caa63e38296e19ad1d8ba4ff77b02f9a49d69 100644 (file)
@@ -598,7 +598,7 @@ gtk_color_swatch_set_rgba (GtkColorSwatch *swatch,
       GtkDragSource *source;
 
       source = gtk_drag_source_new ();
-      content = gdk_content_provider_new_with_callback (GDK_TYPE_RGBA, get_rgba_value, swatch);
+      content = gdk_content_provider_new_with_callback (GDK_TYPE_RGBA, get_rgba_value, swatch, NULL);
       gtk_drag_source_set_content (source, content);
       g_object_unref (content);
       g_signal_connect (source, "drag-begin", G_CALLBACK (gtk_color_swatch_drag_begin), swatch);
@@ -618,7 +618,6 @@ gtk_color_swatch_set_rgba (GtkColorSwatch *swatch,
     {
       gtk_widget_add_css_class (GTK_WIDGET (swatch), "dark");
       gtk_widget_remove_css_class (GTK_WIDGET (swatch), "light");
-
     }
 
   gtk_widget_queue_draw (GTK_WIDGET (swatch));
index 1d8c7901ea2f994b81cb5010e92819e37f2ed6ae..1cd7b1c3a758cdc7082fb42f3bbf080bbac5c7a5 100644 (file)
@@ -6055,7 +6055,8 @@ gtk_icon_view_maybe_begin_drag (GtkIconView *icon_view,
 
   content = gdk_content_provider_new_with_formats (icon_view->priv->source_formats,
                                                    gtk_icon_view_drag_data_get,
-                                                   icon_view);
+                                                   icon_view,
+                                                   NULL);
 
   drag = gdk_drag_begin (surface,
                          device,
@@ -6064,7 +6065,7 @@ gtk_icon_view_maybe_begin_drag (GtkIconView *icon_view,
                          icon_view->priv->press_start_x,
                          icon_view->priv->press_start_y);
 
-   g_object_unref (content);
+  g_object_unref (content);
 
   g_signal_connect (drag, "dnd-finished", G_CALLBACK (gtk_icon_view_dnd_finished_cb), icon_view);
 
index 57fd7172f116e701349a1db9964f62fc34e51771..6f7894defe92ad2acb9195a09883728d8d513567 100644 (file)
@@ -2882,7 +2882,8 @@ gtk_notebook_motion (GtkEventController *controller,
 
       content = gdk_content_provider_new_with_formats (priv->source_targets,
                                                        gtk_notebook_drag_data_get,
-                                                       widget);
+                                                       widget,
+                                                       NULL);
       drag = gdk_drag_begin (surface, device, content, GDK_ACTION_MOVE, priv->drag_begin_x, priv->drag_begin_y);
       g_object_unref (content);
 
index 4ed3f3ae3c42fed0fdfb52412ea8f3e2f6fe4c4c..92bee5066f4431bc59674c3eca5d3fc44d01a3ed 100644 (file)
@@ -3759,7 +3759,8 @@ on_row_dragged (GtkGestureDrag *gesture,
 
       content = gdk_content_provider_new_with_formats (sidebar->source_targets,
                                                        drag_data_get_callback,
-                                                       sidebar);
+                                                       sidebar,
+                                                       NULL);
  
       surface = gtk_native_get_surface (gtk_widget_get_native (GTK_WIDGET (sidebar)));
       device = gtk_gesture_get_device (GTK_GESTURE (gesture));
index 011a97c99c1d30f3798d723394f14727700aaa50..27b0576477b7ec141d57dbd0729a90a5da7e2d28 100644 (file)
@@ -7109,7 +7109,10 @@ gtk_tree_view_maybe_begin_dragging_row (GtkTreeView *tree_view)
 
   surface = gtk_native_get_surface (gtk_widget_get_native (GTK_WIDGET (tree_view)));
   device = gtk_gesture_get_device (GTK_GESTURE (tree_view->drag_gesture)),
-  content = gdk_content_provider_new_with_formats (di->source_formats, gtk_tree_view_drag_data_get, tree_view);
+  content = gdk_content_provider_new_with_formats (di->source_formats,
+                                                   gtk_tree_view_drag_data_get,
+                                                   tree_view,
+                                                   NULL);
 
   drag = gdk_drag_begin (surface, device, content, di->source_actions, start_x, start_y);
 
index 534145998995a817ad65d9e1977882ff63f8e5e6..84ba7abc6ea354a0fa4c2d0690b310cdf4d0f987 100644 (file)
@@ -399,7 +399,7 @@ make_image (const gchar *icon_name, int hotspot)
   gdk_content_formats_builder_add_gtype (builder, G_TYPE_STRING);
   formats = gdk_content_formats_builder_free_to_formats (builder);
 
-  content = gdk_content_provider_new_with_formats (formats, get_data, image);
+  content = gdk_content_provider_new_with_formats (formats, get_data, image, NULL);
   source = gtk_drag_source_new ();
   gtk_drag_source_set_content (source, content);
   gtk_drag_source_set_actions (source, GDK_ACTION_COPY|GDK_ACTION_MOVE|GDK_ACTION_ASK);